package billing.system.logger;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import billing.system.SystemConfigCenter;

public class Logger {
	static Map<String, Logger> loggerMap = new HashMap<String, Logger>();
	private String name;
	static DateFormat dateFormat = new SimpleDateFormat(SystemConfigCenter.get(
			"billing.system.logger.Logger.dateFormat", "yyyy-MM-dd HH:mm:ss"));
	static String logPattern = SystemConfigCenter.get("billing.system.logger.Logger.logPattern",
			"%DATE %NAME [%LEVEL] %MSG");
	static Level baseLevel = Level.valueOf(SystemConfigCenter.get(
			"billing.system.logger.Logger.baseLevel", "INFO"));
	static boolean isPrintStackTrace = Boolean.parseBoolean(SystemConfigCenter.get(
			"billing.system.logger.Logger.isPrintStackTrace", "false"));

	private Logger(String name) {
		this.name = name;
	}

	public static Logger getLogger(Class<?> clazz) {
		String key = clazz.getName();
		Logger value = loggerMap.get(key);
		if (null == value) {
			value = new Logger(key);
			loggerMap.put(key, value);
		}
		return value;
	}

	@Deprecated
	public static Logger getLogger(String className) {
		String key = className;
		Logger value = loggerMap.get(key);
		if (null == value) {
			value = new Logger(key);
			loggerMap.put(key, value);
		}
		return value;
	}

	public void debug(Object message) {
		debug(message, null);
	}

	public void info(Object message) {
		info(message, null);
	}

	public void warn(Object message) {
		warn(message, null);
	}

	public void error(Object message) {
		error(message, null);
	}

	public void error(Exception e) {
		error(e.getMessage(), e);
	}

	public void fatal(Object message) {
		fatal(message, null);
	}

	public void trace(Object message) {
		trace(message, null);
	}

	public void debug(Object message, Throwable e) {
		printLogger(Level.DEBUG, message, e);
	}

	public void info(Object message, Throwable e) {
		printLogger(Level.INFO, message, e);
	}

	public void warn(Object message, Throwable e) {
		printLogger(Level.WARN, message, e);
	}

	public void error(Object message, Throwable e) {
		printLogger(Level.ERROR, message, e);
	}

	public void fatal(Object message, Throwable e) {
		printLogger(Level.FATAL, message, e);
	}

	public void trace(Object message, Throwable e) {
		printLogger(Level.TRACE, message, e);
	}

	private void printLogger(Level level, Object message, Throwable e) {
		StackTraceElement[] StackTraceElements = Thread.currentThread().getStackTrace();
		StackTraceElement stack = null;
		for (StackTraceElement stackTraceElement : StackTraceElements) {
			if (this.getName().equals(stackTraceElement.getClassName())) {
				stack = stackTraceElement;
				break;
			}
		}
		if (level.getLevelValue() >= baseLevel.getLevelValue()) {
			String msg = messageFormat(stack, level, message);
			if (Level.ERROR == level) {
				System.err.println(msg);
			} else {
				System.out.println(msg);
			}
			if (isPrintStackTrace && null != e && e instanceof Exception) {
				e.printStackTrace();
			}
			SysLog.o("run.log", msg);
		}
	}

	private String messageFormat(StackTraceElement stackTraceElement, Level level, Object message) {
		String result = logPattern;
		result = result.replaceAll("%DATE", dateFormat.format(new java.util.Date()));
		result = result.replaceAll("%NAME", name);
		result = result.replaceAll("%LEVEL", level.getUpperCase());
		result = result.replaceAll("%level", level.getLowerCase());
		String METHOD = "non";
		String LINENUMBER = "";
		if (null != stackTraceElement) {
			METHOD = stackTraceElement.getMethodName();
			LINENUMBER = stackTraceElement.getLineNumber() + "";
		}
		result = result.replaceAll("%METHOD", METHOD);
		result = result.replaceAll("%LINENUMBER", LINENUMBER);
		result = result.replaceAll("%STACKTRACE", stackTraceElement + "");;
		String msg = "" + message;
		result = result.replace("%MSG", msg);
		return result;
	}

	public String getName() {
		return this.name;
	}

	public boolean isTraceEnabled() {
		return true;
	}

	public boolean isDebugEnabled() {
		return Level.DEBUG.getLevelValue() >= baseLevel.getLevelValue();
	}

	public void log(String fqcn, Level level, Object message, Throwable e) {
		printLogger(level, message, e);
	}

	public boolean isInfoEnabled() {
		return Level.INFO.getLevelValue() >= baseLevel.getLevelValue();
	}

	public boolean isEnabledFor(Level level) {
		return level.getLevelValue() >= baseLevel.getLevelValue();
	}

	public static void initPrintStackTrace(boolean isP) {
		isPrintStackTrace = isP;
	}

	public static void setBaseLevel(Level baseLevel) {
		System.out.println("baseLevel -> " + baseLevel);
		Logger.baseLevel = baseLevel;
	}

	public boolean isErrorEnabled() {
		return Level.ERROR.getLevelValue() >= baseLevel.getLevelValue();
	}

	public boolean isWarnEnabled() {
		return Level.WARN.getLevelValue() >= baseLevel.getLevelValue();
	}
}
